package com.server.nio.groupchat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * @author @追风少年
 * @description group chat server
 * @date 2022/4/12
 */
public class GroupChatServer {

    private Selector selector;

    private ServerSocketChannel listenChannel;

    private static final int PORT = 8888;

    public GroupChatServer() {

        try {
            // 初始化 属性值
            selector = Selector.open();
            listenChannel = ServerSocketChannel.open();
            // 绑定端口
            listenChannel.socket().bind(new InetSocketAddress(PORT));
            listenChannel.configureBlocking(false);
            // 将listenChannel注册到selector
            listenChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 监听
     */
    public void listen(){
        try {
            while (true) {
                int count = selector.select();

                if (count > 0) {
                    // 有事件处理
                    Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                    while (keyIterator.hasNext()) {
                        SelectionKey key = keyIterator.next();

                        // 监听accept
                        if (key.isAcceptable()){
                            SocketChannel socketChannel = listenChannel.accept();
                            socketChannel.configureBlocking(false);
                            // 将该事件注册到selector
                            socketChannel.register(selector, SelectionKey.OP_READ);
                            // 提示
                            System.out.println(socketChannel.getRemoteAddress() + " 上线了...");
                        }

                        // 通道发送read事件，即通道是可读状态
                        if (key.isReadable()) {
                            // 处理事件
                            readData(key);
                        }

                        keyIterator.remove();
                    }
                } else {
                    System.out.println("等待连接...");
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {

        }

    }

    /**
     * 读取客户端消息
     * @param key
     */
    private void readData(SelectionKey key){
        SocketChannel socketChannel = null;
        try {
            // 得到channel
            socketChannel = (SocketChannel) key.channel();

            // 创建buffer
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            
            int count = socketChannel.read(byteBuffer);
            if (count > 0) {
                // 读取缓冲区数据
                String content = new String(byteBuffer.array());
                // 输出消息
                System.out.println("from 客户端：" + content);

                // 转发，向其他客户端发送消息
                sendInfoToOtherClient(content, socketChannel);
            }
        } catch (IOException e){
            try {
                System.out.println(socketChannel.getRemoteAddress() + " 离线了...");
                // 取消注册
                key.cancel();
                // 关闭通道
                socketChannel.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * 转发消息给其他客户端
     * @param msg
     * @param socketChannelSelf
     */
    private void sendInfoToOtherClient(String msg, SocketChannel socketChannelSelf) throws IOException {
        System.out.println("服务器转发消息中...");
        // 遍历注册到selector上的SocketChannel, 需要排除自身
        for (SelectionKey key : selector.keys()) {
            // 通过key 取出对应的 SocketChannel，用Channel接收
            Channel channel = key.channel();

            // 排除自己，因为自己不需要给自己发送消息
            if (channel instanceof SocketChannel && channel != socketChannelSelf) {
                SocketChannel dest = (SocketChannel) channel;
                // 将消息存到 buffer
                ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));
                // 将buffer数据写到通道
                dest.write(byteBuffer);
            }
        }
    }

    public static void main(String[] args) {
        GroupChatServer groupChatServer = new GroupChatServer();
        groupChatServer.listen();
    }

}
